package com.wanaofu;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

public class MessageHandler implements PhaseListener {
	private static final long serialVersionUID = -7454551624733796686L;

	/**
	 * a name to save messages in the session under
	 */
	private static final String sessionToken = "MULTI_PAGE_MESSAGES_SUPPORT";
	private static final String redirectToken = "MULTI_PAGE_MESSAGES_REDIRECT";
	
	public static final String redirectToken_client_id = "MULTI_PAGE_MESSAGES_REDIRECT_CLIENT_ID";
	

	/**
	 * Return the identifier of the request processing phase during which this
	 * listener is interested in processing PhaseEvent events.
	 */
	public PhaseId getPhaseId() {
		return PhaseId.ANY_PHASE;
	}

	/**
	 * Handle a notification that the processing for a particular phase of the
	 * request processing lifecycle is about to begin.
	 */
	public void beforePhase(PhaseEvent event) {
		if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
			FacesContext facesContext = event.getFacesContext();
			restoreMessages(facesContext);
		}
	}

	/**
	 * Handle a notification that the processing for a particular phase has just
	 * been completed.
	 */
	public void afterPhase(PhaseEvent event) {
		FacesContext facesContext = event.getFacesContext();
		if (PhaseId.RESTORE_VIEW.equals(event.getPhaseId())) {
			Map<String, Object> sessionMap = facesContext.getExternalContext()
					.getSessionMap();
			Integer m = (Integer) sessionMap.get(redirectToken);
			if (null == m) {
				sessionMap.put(redirectToken, 0);
			} else if (m == 0) {
				sessionMap.put(redirectToken, 1);
			} else if (m == 1) {
				sessionMap.put(redirectToken, 0);
			}
		}
		if (event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES
				|| event.getPhaseId() == PhaseId.PROCESS_VALIDATIONS
				|| event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
			saveMessages(facesContext);
		}
	}

	/**
	 * Remove the messages that are not associated with any particular component
	 * from the faces context and store them to the user's session.
	 * 
	 * @return the number of removed messages.
	 */
	@SuppressWarnings("unchecked")
	private int saveMessages(FacesContext facesContext) {
		// remove messages from the context
		List<FacesMessage> messages = new ArrayList<FacesMessage>();
		for (Iterator<FacesMessage> i = facesContext.getMessages(redirectToken_client_id); i
				.hasNext();) {// *********#1 Note "null" *****//
		// *********Just store faces messages with the null value clientid ,if
		// the clientId of messages were not null,***********//
		// *******will not store; You can modify here to store them********//
			messages.add((FacesMessage) i.next());
			i.remove();
		}
		// store them in the session
		if (messages.size() == 0) {
			return 0;
		}
		Map<String, Object> sessionMap = facesContext.getExternalContext()
				.getSessionMap();
		// if there already are messages
		List<FacesMessage> existingMessages = (List<FacesMessage>) sessionMap
				.get(sessionToken);
		if (existingMessages != null) {
			existingMessages.addAll(messages);
		} else {
			sessionMap.put(sessionToken, messages); // if these are the first
													// messages
		}
		return messages.size();
	}

	/**
	 * Remove the messages that are not associated with any particular component
	 * from the user's session and add them to the faces context.
	 * 
	 * @return the number of removed messages.
	 */
	@SuppressWarnings("unchecked")
	private int restoreMessages(FacesContext facesContext) {
		// remove messages from the session
		Map sessionMap = facesContext.getExternalContext().getSessionMap();
		Integer m = (Integer) sessionMap.get(redirectToken);
		List messages = (List) sessionMap.remove(sessionToken);
		sessionMap.put(redirectToken, 0);
		if (m == 1) { // not redirect--ajax request
			return 0;
		} else { // redirect request
			// store them in the context
			if (messages == null) {
				return 0;
			}
			int restoredCount = messages.size();
			for (Iterator i = messages.iterator(); i.hasNext();) {
				facesContext.addMessage(null, (FacesMessage) i.next());
			}
			return restoredCount;
		}
	}
}
